/*
 * dvbt.cpp - DVB-t interface
 *
 * Copyright (C) 2010-2011 Serge Begger
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "dvbt.h"
#include "ui_dvbt.h"

dvbt::dvbt(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::dvbt)
{
    ui->setupUi(this);
    ui->channelTableView->hide();
    ui->pushButDw->hide();
    ui->pushButUp->hide();
    initEnums();
    progressbar = new myProgressbar(0,"Please wait... Scan progress...");
    scanProc = new QProcess(this);

    settings = new QSettings("carpc", "dvbt", this);
    settings->setPath(QSettings::IniFormat,QSettings::UserScope,"carpc");
    currCh = settings->value("currCh").toInt();    
    currVolume = settings->value("currVolume").toInt();
    ui->lcdCh->display(currCh+1);    

    gstEngine = new gstengine(this);
    connect(gstEngine, SIGNAL(toFullScreen()),this,SLOT(toFullScreen()));
}

dvbt::~dvbt()
{
    settings->setValue("currCh",currCh);
    settings->setValue("currVolume",currVolume);
    gstEngine->~gstengine();
    if (!db.isOpen()) {
        db.close();
    }
    delete ui;
}

void dvbt::setVolume(int vol) {
    currVolume = vol;
    gstEngine->setVolume(vol);
    settings->setValue("currVolume"  , currVolume);
}

bool dvbt::init()
{
    if (!initDbConnection())
        return false;

    modelChannels = new QSqlRelationalTableModel(this);
    modelChannels->setTable("dvbtchannels");
    modelChannels->select();
    ui->channelTableView->setModel(modelChannels);
    ui->channelTableView->setColumnHidden(0,true);
    for (int i=2; i<13; ++i)
        ui->channelTableView->setColumnHidden(i,true);

    if (modelChannels->rowCount() == 0) {
        myMessage message(0);
        message.exec(3,"Channel list empty. \n Scan now?");
        if (message.result)
            on_findButton_pressed();
        else
            return false;
    }

    if (modelChannels->rowCount() == 0)
        return false;

    if (!initVideo())
        return false;

    setVolume(currVolume);
    return true;
}

void dvbt::on_chButton_pressed()
{
    gstEngine->setGeometryWV(QRect(0,0,380,200));
    ui->pushButDw->show();
    ui->pushButUp->show();
    ui->channelTableView->show();
}

void dvbt::toFullScreen()
{
    if (ui->channelTableView->isVisible()) {
        ui->channelTableView->hide();
        ui->pushButDw->hide();
        ui->pushButUp->hide();
    }
}

void dvbt::on_backButton_pressed()
{
    emit hideWidget();
}

void dvbt::on_closeButton_pressed()
{
    this->~dvbt();
}

void dvbt::on_pushButUp_pressed()
{
    int currRow = ui->channelTableView->currentIndex().row() - 1;
    if (currRow < 0)
        currRow = 0;
    ui->channelTableView->selectRow(currRow);
}

void dvbt::on_pushButDw_pressed()
{
    int currRow = ui->channelTableView->currentIndex().row() + 1;
    if (currRow > modelChannels->rowCount())
        currRow = modelChannels->rowCount();
    ui->channelTableView->selectRow(currRow);
}

void dvbt::on_findButton_pressed()        
{
    myMessage message(0);
    message.exec(3,"Scan now?");
    if (!message.result)
        return;
    if (!QFile::exists("/usr/bin/w_scan")) {
        message.exec(0,"w-scan not found!!! Install it...");
        return;
    }

    gstEngine->stopPipeline();

    scanProc->setReadChannel(QProcess::StandardOutput);
    connect(scanProc,SIGNAL(finished(int)),this,SLOT(endScan(int)));
    connect(scanProc,SIGNAL(readyReadStandardOutput()),this,SLOT(parceScan()));
    scanProc->start("/usr/bin/w_scan -ft -cDE -X");
    progressbar->start();
}

void dvbt::parceScan()
{
    int TV = 0;int RA = 0;
    if (db.isOpen()) {
        progressbar->stop();
        QTextStream ts(scanProc->readAllStandardOutput());
        modelChannels->removeRows(0,modelChannels->rowCount());
        while (!ts.atEnd())
        {
            QString line = ts.readLine();
            QList<QString> items = line.split(":");
            int row = modelChannels->rowCount();
            modelChannels->insertRows(row, 1);
            if(items.at(10) == "0") {
                modelChannels->setData(modelChannels->index(row, 0), "RA");
                RA++;
            } else {
                modelChannels->setData(modelChannels->index(row, 0), "TV");
                TV++;
            }
            for (int i = 1; i < 11; ++i) {
                modelChannels->setData(modelChannels->index(row, i), items.at(i-1));
            }
            QString pids;
            pids.append(items.at(10));
            pids.append(":");
            pids.append(items.at(11));
            pids.append(":");
            pids.append(items.at(12));
            modelChannels->setData(modelChannels->index(row, 11), pids);
            modelChannels->submitAll();
        }
    }
    myMessage message(0);
    if (modelChannels->rowCount() != 0) {
        message.exec(1,"Found "+QString::number(TV)+" TV and "+QString::number(RA)+" radio channel.");
        currCh = 0;
        changeChannel();
    } else {
        message.exec(0,"Channel not found!");
    }
}

void dvbt::endScan(int err)
{
    progressbar->stop();
    if (err != 0) {
        myMessage message(0);
        message.exec(0,"Scan error!");
    }
    currCh = 0;
}

void dvbt::on_prevButton_pressed()
{
    currCh--;
    if (currCh < 0)
        currCh = 0;
    changeChannel();
}

void dvbt::on_nextButton_pressed()
{
    currCh++;
    if (currCh == modelChannels->rowCount())
        currCh = modelChannels->rowCount()-1;
    changeChannel();
}

void dvbt::on_channelTableView_pressed(QModelIndex index)
{
    if (index.isValid()) {
        currCh = index.row();
        ui->channelTableView->setCurrentIndex(index);
        changeChannel();
    }
}

void dvbt::changeChannel()
{
   gstEngine->stopPipeline();
   initVideo();
   ui->lcdCh->display(currCh+1);
}

QString dvbt::getMapValue(QMap<QString,QString> *map, int column) {
    QString val = getDbValue(column);
    if (!val.isEmpty())
        return map->find(val).value();
    else
        return map->begin().value();
}

QString dvbt::getDbValue(int column) {
    QModelIndex index = modelChannels->index(currCh,column);
    if (index.isValid())
        return modelChannels->data(index).toString();
    else
        return "";
}

bool dvbt::initVideo()
{
    QStringList paramList;
    typeCh = getDbValue(0);
    paramList.append(getDbValue(0));
    paramList.append(getMapValue(modulation,7));
    paramList.append(getMapValue(trans_mode,8));
    paramList.append(getMapValue(bandwidth,4));
    paramList.append(getDbValue(2));
    paramList.append(getMapValue(code_rate,5));
    paramList.append(getMapValue(code_rate,6));
    paramList.append(getMapValue(guard,9));
    paramList.append(getMapValue(hierarchy,10));
    paramList.append(getDbValue(11));
    if (!gstEngine->initDVB(ui->frameVideo, paramList))
        return false;
    if (!gstEngine->getStatePipeline())
        return false;
    if (typeCh == "RA") {
        ui->channelTableView->show();
        ui->pushButDw->show();
        ui->pushButUp->show();
        modelChannels->select();
    } else {
        ui->channelTableView->hide();
        ui->pushButDw->hide();
        ui->pushButUp->hide();
        gstEngine->setGeometryWV(QRect(0,0,796,491));
        gstEngine->setVideoLCDtext(getDbValue(1));
    }
    return true;
}

bool dvbt::initDbConnection()
{
    if(QSqlDatabase::contains(QSqlDatabase::defaultConnection)) {
        db = QSqlDatabase::database();
    } else {
        db = QSqlDatabase::addDatabase("QSQLITE");
    }
    db.setDatabaseName(QDir::homePath() + "/qcarpc.db");
    if (!db.open()) {
        myMessage message(0);
        message.exec(0,"Cannot open qcarpc database!");
        return false;
    }

    QStringList dbtables = db.tables(QSql::Tables);
    if (dbtables.contains( tr("dvbtchannels"), Qt::CaseInsensitive)) {
        return true;
    } else {
        QSqlQuery query;

        query.exec("create table dvbtchannels ( type varchar(2),       "
                                     "name varchar(50),        "
                                     "freq varchar(9),         "
                                     "inversion varchar(20),   "
                                     "bandwidth varchar(20),   "
                                     "code_rate_lp varchar(20),"
                                     "code_rate_hp varchar(20),"
                                     "modulation varchar(10),"
                                     "trans_mode varchar(20),"
                                     "guard varchar(50),"
                                     "hierarchy varchar(50),"
                                     "pids varchar(50) )");    
        return true;
    }
}

void dvbt::initEnums()
{
    inversion = new QMap<QString,QString>;
    inversion->insert("INVERSION_OFF","0");
    inversion->insert("INVERSION_ON","1");
    inversion->insert("INVERSION_AUTO","2");

    bandwidth = new QMap<QString,QString>;
    bandwidth->insert("BANDWIDTH_8_MHZ","0");
    bandwidth->insert("BANDWIDTH_7_MHZ","1");
    bandwidth->insert("BANDWIDTH_6_MHZ","2");
    bandwidth->insert("BANDWIDTH_AUTO","3");

    code_rate = new QMap<QString,QString>;
    code_rate->insert("FEC_NONE","0");
    code_rate->insert("FEC_1_2","1");
    code_rate->insert("FEC_2_3","2");
    code_rate->insert("FEC_3_4","3");
    code_rate->insert("FEC_4_5","4");
    code_rate->insert("FEC_5_6,","5");
    code_rate->insert("FEC_6_7","6");
    code_rate->insert("FEC_7_8","7");
    code_rate->insert("FEC_8_9","8");
    code_rate->insert("FEC_AUTO","9");
    code_rate->insert("FEC_3_5","10");
    code_rate->insert("FEC_9_10","11");

    modulation = new QMap<QString,QString>;
    modulation->insert("QPSK","0");
    modulation->insert("QAM_16","1");
    modulation->insert("QAM_32","2");
    modulation->insert("QAM_64","3");
    modulation->insert("QAM_128","4");
    modulation->insert("QAM_256","5");
    modulation->insert("QAM_AUTO","6");
    modulation->insert("VSB_8","7");
    modulation->insert("VSB_16","8");
    modulation->insert("PSK_8","9");
    modulation->insert("APSK_16","10");
    modulation->insert("APSK_32","11");
    modulation->insert("DQPSK","12");

    trans_mode = new QMap<QString,QString>;
    trans_mode->insert("TRANSMISSION_MODE_2K","0");
    trans_mode->insert("TRANSMISSION_MODE_8K","1");
    trans_mode->insert("TRANSMISSION_MODE_AUTO","2");
    trans_mode->insert("TRANSMISSION_MODE_4K","3");

    guard = new QMap<QString,QString>;
    guard->insert("GUARD_INTERVAL_1_32","0");
    guard->insert("GUARD_INTERVAL_1_16","1");
    guard->insert("GUARD_INTERVAL_1_8","2");
    guard->insert("GUARD_INTERVAL_1_4","3");
    guard->insert("GUARD_INTERVAL_AUTO","4");

    hierarchy = new QMap<QString,QString>;
    hierarchy->insert("HIERARCHY_NONE","0");
    hierarchy->insert("HIERARCHY_1","1");
    hierarchy->insert("HIERARCHY_2","2");
    hierarchy->insert("HIERARCHY_4","3");
    hierarchy->insert("HIERARCHY_AUTO","4");
}
